#include "socket.h"
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <arpa/inet.h>

bool TcpServer::serverInit(const uint16_t in_port) {
    if ((m_listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;
        return false;
    }

    int opt = 1;
    if (setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        std::cerr << "Setsockopt failed: " << strerror(errno) << std::endl;
        close(m_listenfd);
        m_listenfd = -1;
        return false;
    }

    m_port = in_port;

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(m_port);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(m_listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
        std::cerr << "Bind failed: " << strerror(errno) << std::endl;
        close(m_listenfd); 
        m_listenfd = -1; 
        return false; 
    }

    if (listen(m_listenfd, 5) == -1) {
        std::cerr << "Listen failed: " << strerror(errno) << std::endl;
        close(m_listenfd); 
        m_listenfd = -1; 
        return false;
    }
    return true;
}

bool TcpServer::accept() {
    struct sockaddr_in caddr;
    socklen_t addrlen = sizeof(caddr);

    if ((m_clientfd = ::accept(m_listenfd, (struct sockaddr *)&caddr, &addrlen)) == -1) {
        std::cerr << "Accept failed: " << strerror(errno) << std::endl;
        return false;
    }
    m_clientip = inet_ntoa(caddr.sin_addr);
    return true;
}

const std::string& TcpServer::clientIp() const {
    return m_clientip;
}

bool TcpServer::send(const std::string& buffer) {
    if (m_clientfd == -1) return false;
    if (::send(m_clientfd, buffer.c_str(), buffer.size(), 0) == -1) {
        return false;
    }
    std::cout << "Sent: " << buffer << std::endl;
    return true;
}

bool TcpServer::recv(std::string& buffer, const size_t maxLen) {
    buffer.clear();
    buffer.resize(maxLen);
    int readn = ::recv(m_clientfd, &buffer[0], buffer.size(), 0);
    if (readn <= 0) {
        buffer.clear(); 
        return false;
    }
    buffer.resize(readn);
    std::cout << "Received: " << buffer << std::endl;
    return true;
}

bool TcpServer::closeListen() {
    if (m_listenfd == -1) return false; 
    ::close(m_listenfd);
    m_listenfd = -1;
    return true;
}

bool TcpServer::closeClient() {
    if (m_clientfd==-1) return false;
    ::close(m_clientfd);
    m_clientfd = -1;
    return true;
}